#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "../structure.h"


#define SERVER_PORT 1500
#define CLIENT_PORT 1234
#define MAX_MSG 80


// certaines variables sont globales (pour le threading)
paquet msg_recu ; 
int sd_reception, flag=0, n, double_envoi=0, buffer_plein=0, congestion=0 ;
struct sockaddr_in CtoS_sender, CtoS_receiver, StoC_sender, StoC_receiver;



void thread_reception(){
	// cette fonction sera appelée via un thread
	// il se chargera de vérifier si un message arrive sur la socket de reception
	
	printf("Thread lancé \n") ;
	for (;;) {
		int StoC_senderLen = sizeof(StoC_sender);
		n = recvfrom(sd_reception, &msg_recu, MAX_MSG, 0,(struct sockaddr *)&StoC_sender, (socklen_t*)&StoC_senderLen);
		if (n<0) {
			perror("Client");
			 exit(0);
		}
		
		//Message reçu
		printf("Message reçu (ACK: %d, FLUX: %d, FLAG: %d)\n", msg_recu.ack, msg_recu.flux, msg_recu.flag) ;
		//Si ack négatif
		if((msg_recu.ack==1)&&(msg_recu.flux==0)&&(msg_recu.flag==1))
		{
			double_envoi=1 ;
		}
		else if((msg_recu.ack==1)&&(msg_recu.flux==1)&&(msg_recu.flag==1))
		{
			//Si buffer plein
			buffer_plein=1;
		}
		else if((msg_recu.ack==1)&&(msg_recu.flux==1)&&(msg_recu.flag==0))
		{
			//Si buffer vide
                        buffer_plein=0;
                }
                        

			//Si on Detecte Congestion :
			//congestion=0;
                

	}// fin for (boucle infinie reception)
	
	
}




void construire_message(char* data_, int numSeq, paquet* mesg_) {
	if(mesg_==NULL) {
	mesg_= malloc(sizeof(paquet));
	}

	//Numéro du block
	int numBlock_=numSeq/8;

	//Numéro du paquet (1 block contient 8 paquets)
	int numPaquet_=numSeq%8;

	//Récupération du numéro de block
	mesg_->numBlock=numBlock_;

	//Récupération du numéro de paquet
	mesg_->numPaquet=numPaquet_; 
	
	//Initialisation d'un paquet de data : ack=0 flux=0 flag=0
	//Si ack=0 c'est de la data
	mesg_->ack=0;

	//Gestion des flux (buffer)
	mesg_->flux=0;

	//Gestion de la congestion
	mesg_->flag=0;

	if ( strlen(data_) < 100)  {
		strcpy(mesg_->data,data_);

	}
  
}


void init_messsage_fin(paquet* mesg_){

	//Message 0 1 1 pour fin d'emission
        if(mesg_==NULL) {
        mesg_= malloc(sizeof(paquet));
        }

        //Si ack=0 c'est de la data
        mesg_->ack=0;

        //Gestion des flux (buffer)
        mesg_->flux=1;

        //Pour la gestion de congestion
        mesg_->flag=1;
}





int main (int argc, char *argv[]) {
	paquet a_envoyer;
	int sd_envoi ;
	
	pthread_t thread ;
	void * ret ;

	//CtoS : communication Client => Serveur
	//StoC : communication Serveur => Client

	//Si le nombre d'arguments est pas respecté
	if (argc < 2) {
		printf ("usage: %s server_ip\n",argv[0]);
		exit(1);
	}

	// Creation et bind du socket de reception
	if ((sd_envoi = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
		perror(argv[0]);
		exit(1);
	}

	CtoS_sender.sin_family = AF_INET;
	CtoS_sender.sin_addr.s_addr = htonl(INADDR_ANY);
	CtoS_sender.sin_port = htons(0);
	if (bind(sd_envoi,(struct sockaddr *)&CtoS_sender, sizeof(CtoS_sender)) < 0) {
		perror(argv[0]);
		exit(1);
	}

	/* Fill server address structure */
	CtoS_receiver.sin_family = AF_INET;
	if (inet_aton(argv[1], &(CtoS_receiver.sin_addr))==0) {
		printf("%s: Server's IP address problem ! (%s)\n", argv[0], argv[1]);
		exit(1);
	}

	CtoS_receiver.sin_port = htons(SERVER_PORT);
	
	
	

	// Creation et bind du socket de reception
	if ((sd_reception = socket(PF_INET,SOCK_DGRAM, 0)) < 0) {
		perror(argv[0]);
		exit(1);
	}
	StoC_receiver.sin_family = AF_INET;
	StoC_receiver.sin_addr.s_addr = htonl(INADDR_ANY);
	StoC_receiver.sin_port = htons(CLIENT_PORT);
	if (bind(sd_reception, (struct sockaddr *)&StoC_receiver, sizeof(StoC_receiver)) < 0) {
		perror(argv[0]);
		exit(1);
	}

///////////////////////////////////////////////////////////////////////////////


	// variables
	int nb_lignes=0 ;
	char *file = "hugues.txt" ;
	char ligne_lue[512] = "";
	FILE *fic ;

	// création du thread de réception
/*	if(pthread_create(&thread, NULL, thread_reception, NULL) < 0){
		fprintf(stderr, "Erreur de création du Thread de réception : pthread_create\n") ;
		exit (1) ;
	} // fin if
	(void)pthread_join(thread, &ret) ;
*/




	// ouverture fichier
	fic = fopen(file, "r"); // ouvrir en lecture
	if(fic == NULL){
      printf("Impossible d'ouvrir le fichier %s\n", file);
      exit(1);
  }

	while(fgets(ligne_lue, 512, fic) != NULL){
    
		construire_message(ligne_lue, nb_lignes, &a_envoyer);
		if (sendto(sd_envoi, &a_envoyer, sizeof(a_envoyer), 0,(struct sockaddr *)&CtoS_receiver, sizeof(CtoS_receiver)) < 0){
			perror(argv[0]); exit(1);
		} else {
			printf("%s: Sent to %s (block %d, paquet %d):\n==> %s",argv[0], inet_ntoa(CtoS_receiver.sin_addr), a_envoyer.numBlock, a_envoyer.numPaquet, ligne_lue);
		}
    
		nb_lignes++ ;
	} // fin while (lecture fichier)
	
	
	// fermeture fichier
	if(fclose(fic) == EOF) {
      printf("Probleme de fermeture du fichier %s", file);
      exit(1);
	}
	
	
	// envoi du paquet de fin de transmission
	init_messsage_fin(&a_envoyer);
	printf("Envoi du paquet de fin de transmission\n");
		if (sendto(sd_envoi, &a_envoyer, sizeof(a_envoyer), 0,(struct sockaddr *)&CtoS_receiver, sizeof(CtoS_receiver)) < 0){
			perror(argv[0]); exit(1);
		}
	


		
	close(sd_envoi);
	return 0;
}

